/*
 * snmp_asn.cpp
 *
 *  Created on: 2016-11-8
 *      Author: root
 */

#include"snmp_asn.h"
#include"PublicLog.h"
#include<sys/types.h>
#include<string.h>

const char ASNNULL[2]={0x05,0x00};

int MakeAsnStringData(char*data,int len,u_char type,const char*valstr,int vallen){
    int datalen=MakeAsnLengthData(data,0,type,vallen);
    memcpy(data+datalen,valstr,vallen);
    datalen+=vallen;
    return datalen;
}
int MakeAsnObjectIDData(char*data,int len,uint32_t*oidName,int oidLen){
    int  oidreallen=0;
    char*oiddata=data;
    int  i=0;
    if(oidName[0]==1&&oidName[1]==3){
		oiddata[0]=0x2b;
		oidreallen=1;
    }else{
		WRONG("AddSnmpObjectID");
		return -1;
    }
    for(i=2;i<oidLen;i++){
		if(oidName[i]<(unsigned)0x80){
			oiddata[oidreallen]=oidName[i];
			oidreallen+=1;
		}else
		if(oidName[i]<(unsigned)0x4000){
			oiddata[oidreallen+0]=(u_char)((oidName[i]>>7)|0x80);
			oiddata[oidreallen+1]=(u_char)(oidName[i]&0x07f);
			oidreallen+=2;
		}else
		if(oidName[i]<(unsigned)0x200000){
			oiddata[oidreallen+0]=(u_char)((oidName[i]>>14)|0x80);
			oiddata[oidreallen+1]=(u_char)((oidName[i]>>7&0x7f)|0x80);
			oiddata[oidreallen+2]=(u_char)(oidName[i]&0x07f);
			oidreallen+=3;
		}else
		if(oidName[i]<(unsigned)0x10000000){
			oiddata[oidreallen+0]=(u_char)((oidName[i]>>21)|0x80);
			oiddata[oidreallen+1]=(u_char)((oidName[i]>>14&0x7f)|0x80);
			oiddata[oidreallen+2]=(u_char)((oidName[i]>>7&0x7f)|0x80);
			oiddata[oidreallen+3]=(u_char)(oidName[i]&0x07f);
			oidreallen+=4;
		}else{
			oiddata[oidreallen+0]=(u_char)((oidName[i]>>28)|0x80);
			oiddata[oidreallen+1]=(u_char)((oidName[i]>>21&0x7f)|0x80);
			oiddata[oidreallen+2]=(u_char)((oidName[i]>>14&0x7f)|0x80);
			oiddata[oidreallen+3]=(u_char)((oidName[i]>>7&0x7f)|0x80);
			oiddata[oidreallen+4]=(u_char)(oidName[i]&0x07f);
			oidreallen+=5;
        }
    }
	return oidreallen;
}
int MakeAsnObjectIDData(char*data,int len,u_char type,uint32_t*oidName,int oidLen){
    char oiddata[128]={0};
    int  oidreallen=MakeAsnObjectIDData(oiddata,0,oidName,oidLen);
    int  datalen=MakeAsnLengthData(data,0,type,oidreallen);
    memcpy(data+datalen,oiddata,oidreallen);
    datalen+=oidreallen;
    return datalen;
}
int MakeAsnIntData(char*data,int len,u_char type,int number,int length){
    data[0]=type;
    data[1]=length;
    char*Pos=(char*)&number;
    int i=0;
    while(i<length){
		data[i+2]=Pos[length-i-1];
		i++;
    }
    return length+2;
}
int MakeAsnRequestData(char*data,int len,uint32_t*oidName,int oidLen){
    char oiddata[1024]={0};
    int  oidlen=0;
    int  datalen=0;
    oidlen=MakeAsnObjectIDData(oiddata,len,ASN_OBJECT_ID,oidName,oidLen);
    datalen=MakeAsnLengthData(data,0,ASN_SEQUENCE,oidlen+2);
    memcpy(data+datalen,oiddata,oidlen);
    datalen+=oidlen;
    memcpy(data+datalen,ASNNULL,2);
    datalen+=2;
    return datalen;
}
int MakeAsnLengthData(char*data,int len,u_char type,int length){
    int datalen=0;
    data[0]=type;
    if(length<0x80){
		data[1]=length;
		datalen=1;
    }else
    if(length<=0xFF){
		data[1]=0x81;
		data[2]=length;
		datalen=2;
    }else{
		data[1]=0x82;
		data[2]=(u_char)((length >>8)&0xFF);
		data[3]=(u_char)(length & 0xFF);
		datalen=3;
    }
    return datalen+1;
}
const char*ReadAsnLengthData(const char*data,int len,u_char type,int&length){
    if((u_char)data[0]!=(u_char)type){
		WRONG("类型不一致[理想:%hhu 实际:%hhu]",type,data[0]);
        return data;
    }
    if((u_char)data[1]<(u_char)0x80){
        length=data[1];
        return data+2;
    }
    if((u_char)data[1]==(u_char)0x81){
        length=data[2]&0xff;
        return data+3;
    }
    if((u_char)data[1]==(u_char)0x82){
        length=(data[3]&0xff)+((data[2]<<8)&0xff00);
        return data+4;
    }
    WRONG("未处理%s %d",__FUNCTION__,__LINE__);
    return data;
}
//获取分割包长度
//限制ASN_SEQUENCE
const char*ReadAsnSequenceLength(const char*data,int len,int&length){
    return ReadAsnLengthData(data,len,ASN_SEQUENCE,length);
}
//读取整数
//限制ASN_INTEGER/ASN_TIMETICKS/ASN_GAUGE
const char*ReadAsnIntData(const char*data,int len,u_char type,int32_t&number){
    int vallen=0;
    const char*Pos=ReadAsnLengthData(data,len,type,vallen);
	do{
		int i=0;
		number=0;
		while(i<vallen){
			number*=256;
			number+=(((u_char)Pos[i])&0xff);
			i++;
		}
	}while(0);
    return Pos+vallen;
}
//读取OBJECTID
//限制类型ASN_OBJECT_ID
const char*ReadAsnObjectIDData(const char*data,int len,uint32_t*oidName,int&oidLen){
    int vallen=0;
    const char*Pos=ReadAsnLengthData(data,len,ASN_OBJECT_ID,vallen);
    int i=0;
    int j=0;
    for(i=0;i<vallen;i++){
        uint32_t val=Pos[i]&0xff;
        if(i==0){
			if(val==0x2B){
				oidName[j++]=1;
				oidName[j++]=3;
			}else
			if(val<40){
				oidName[j++]=val;
			}else
			if(val<80){
				oidName[j++]=val-40;
			}else{
				oidName[j++]=val-80;
            }
        }else{
			int tmpval=0;
			while(val>0x80){
				tmpval*=128;
				tmpval+=val&0x7F;
				i++;
				val=Pos[i]&0xff;
            }
			tmpval*=128;
			tmpval+=val;
			oidName[j++]=tmpval;
        }
    }
    oidLen=j;
    return Pos+vallen;
}
